/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.webbapps.cormac_susilo.core;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.RollbackException;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

/**
 * Implements model/database methods specific to the Run entities
 * @author simon, Tor
 */
public final class RunRegistry extends AbstractDAO<Run, Long> {

    private RunRegistry(String puName) {
        super(Run.class, puName);
    }

    public static RunRegistry newInstance(String puName) {
        return new RunRegistry(puName);
    }

    /**
     * Returns unique track names for the given user
     * @param user_id
     * @return a list of unique track names, in ascending order
     */
    public List<String> getTrackNamesByUserId(long user_id) {
        EntityManager em = super.getEM();

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<String> cq = cb.createQuery(String.class);
        Root<Run> run = cq.from(Run.class);
        //add group by
        cq.select(run.get(Run_.trackname)).distinct(true);
        cq.where(cb.equal(run.get(Run_.user).get(User_.id), user_id));
        cq.orderBy(cb.asc(run.get(Run_.trackname)));

        List<String> result = em.createQuery(cq).getResultList();
        em.close();

        return result;
    }
    /**
     * Returns the Runs for the given user
     * @param user_id the user id
     * @return a list of Run in no specific order
     */
    public List<Run> getByUserId(long user_id) {

        EntityManager em = super.getEM();

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Run> cq = cb.createQuery(Run.class);
        Root<Run> run = cq.from(Run.class);
        //add group by
        cq.where(cb.equal(run.get(Run_.user).get(User_.id), user_id));

        List<Run> result = em.createQuery(cq).getResultList();
        em.close();

        return result;
    }
    
    @Deprecated
    public List<Run> getByName(String run_trackname) {
        EntityManager em = super.getEM();

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Run> cq = cb.createQuery(Run.class);
        Root<Run> run = cq.from(Run.class);
        
        cq.where(cb.equal(run.get(Run_.trackname), run_trackname));

        List<Run> result = em.createQuery(cq).getResultList();
        em.close();

        return result;
    }
    
    /**
     * Return the runs for a given user and track name
     * @param user_id the user id
     * @param run_trackname the track name 
     * @return a list of runs in date ordering
     */
    public List<Run> getByUserAndName(long user_id, String run_trackname) {
        EntityManager em = super.getEM();

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Run> cq = cb.createQuery(Run.class);
        Root<Run> run = cq.from(Run.class);

        Predicate a = cb.equal(run.get(Run_.trackname), run_trackname);
        Predicate b = cb.equal(run.get(Run_.user).get(User_.id), user_id);
        Predicate p = cb.and(a,b);
        
        cq.where(p);
        cq.orderBy(cb.desc(run.get(Run_.run_date)));
        
        List<Run> result = em.createQuery(cq).getResultList();
        em.close();

        return result;
    }
    
    /**
     * Update the track name of all matching Run for the given user
     * @param user_id the use id
     * @param run_trackname the old track name
     * @param new_trackname the new track name
     * @throws RollbackException if en error occurs during the database operation
     */
    public void changeTrackNames(long user_id, String run_trackname, String new_trackname) throws RollbackException {       
        List<Run> result = getByUserAndName(user_id, run_trackname);
        
        EntityManager em = super.getEM();
        EntityTransaction tx = em.getTransaction();
        try {
            
            tx.begin();
            
            for (Run r : result) {
                r.setTrackname(new_trackname);            
                em.merge(r);
            }
            
            tx.commit();
            
        } catch (RollbackException e) {
            if (tx.isActive()) {
                tx.rollback();
            }
            Logger.getLogger(AbstractDAO.class.getName()).log(Level.SEVERE, "Exception during Update operation", e);
            throw e;
        } finally {
            if (em.isOpen()) {
                em.close();
            }
        }
    }
}
